import datetime

from django.db import transaction
from django.http import HttpResponse
from rest_framework.decorators import action
from rest_framework.mixins import ListModelMixin
from rest_framework.permissions import IsAuthenticated, AllowAny
from rest_framework.response import Response

import settings
from social.exceptions import CodeException
from social.payment.models import Wallet, Product, Order, WalletRecord
from social.payment.payment import WxPay
from social.payment.serializers import WalletSerializers, VIPProductSerializer, CoinProductSerializer, \
    WalletRecordSerializer
from social.utils.utils import md5_hash
from social.utils.views import BaseGenericViewSet


class PaymentViewSet(BaseGenericViewSet, ListModelMixin):
    queryset = Wallet.objects
    permission_classes = (IsAuthenticated,)
    pagination_ordering = '-created_at'

    @action(methods=['GET'], detail=False)
    def wallet(self, request, *args, **kwargs):
        wallet, _ = Wallet.objects.get_or_create(user=request.user)
        return Response(data=WalletSerializers(wallet).data)

    @action(methods=['POST'], detail=False)
    def bind_alipay(self, request, *args, **kwargs):
        wallet, _ = Wallet.objects.get_or_create(user=request.user)
        wallet.alipay = request.data.get('alipay')
        wallet.save(update_fields=['alipay'])
        return Response(data=WalletSerializers(wallet).data)

    @action(methods=['POST'], detail=False)
    def withdraw(self, request, *args, **kwargs):
        with transaction.atomic():
            wallet, _ = Wallet.objects.get_or_create(user=request.user)
            amt = request.data.get('amt')
            if amt not in [3000, 5000, 30000, 50000, 100000, 200000]:
                raise CodeException(msg='提现金额错误')
            wallet.withdraw(amt)
            WalletRecord.objects.create(user=request.user, change=-amt, title='提现中', type=WalletRecord.WITHDRAW)
            wallet.refresh_from_db()
            return Response(data=WalletSerializers(wallet).data)

    @action(methods=['GET'], detail=False, serializer_class=VIPProductSerializer)
    def vip_products(self, request, *args, **kwargs):
        self.pagination_ordering = '-sort'
        self.queryset = Product.objects.filter(type=Product.VIP)
        return super(PaymentViewSet, self).list(request, *args, **kwargs)

    @action(methods=['GET'], detail=False, serializer_class=CoinProductSerializer)
    def coin_products(self, request, *args, **kwargs):
        self.pagination_ordering = 'coin'
        self.queryset = Product.objects.filter(type=Product.COIN)
        return super(PaymentViewSet, self).list(request, *args, **kwargs)

    @action(methods=['GET'], detail=False, serializer_class=WalletRecordSerializer)
    def wallet_record(self, request, *args, **kwargs):
        _type = request.GET.get('type')
        if _type == 'income':
            self.queryset = WalletRecord.objects.filter(user=request.user,
                                                        type__in=[WalletRecord.WITHDRAW, WalletRecord.INCOME])
        else:
            self.queryset = WalletRecord.objects.filter(user=request.user, type=_type)
        return super(PaymentViewSet, self).list(request, *args, **kwargs)

    @action(methods=['POST'], detail=False, permission_classes=(AllowAny,))
    def wxpay_callback(self, request, *args, **kwargs):
        wxpay = WxPay()
        if wxpay.handle_callback(request.body):
            html = """<xml>
                         <return_code><![CDATA[SUCCESS]]></return_code>
                         <return_msg><![CDATA[OK]]></return_msg>
                       </xml>"""
            return HttpResponse(html, content_type="text/xml")
        return Response(status=400)

    @action(methods=['POST'], detail=False)
    def pay(self, request, *args, **kwargs):
        product_id = request.data.get('product_id')
        product = Product.objects.get(id=product_id)
        amount = 1 if settings.DEBUG else product.price
        order = Order.objects.create(amount=amount, user=request.user, product=product,
                                     out_trade_no=md5_hash(datetime.datetime.now().timestamp()))
        payment = WxPay()
        data = {
            'trade_type': 'APP',
            'total_amount': amount,
            'subject': '秀币充值' if product.type == Product.COIN else 'VIP充值',
            'out_trade_no': order.out_trade_no
        }
        res = payment.trade_app(data)
        return Response(data=res)
